package com.harth.blemultiplatform.ble

import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flow
import platform.CoreBluetooth.CBCentralManager
import platform.CoreBluetooth.CBCentralManagerDelegateProtocol
import platform.CoreBluetooth.CBPeripheral
import platform.Foundation.NSNumber
import platform.darwin.NSObject
import kotlin.time.Duration

class NativeCentralManager: ICentralManager{

    private val protocol = NativeCentralManagerProtocol()
    val centralManager: CBCentralManager by lazy{
        CBCentralManager().apply {
            setDelegate(protocol)
        }
    }

    override fun getPeripheralsById(ids: List<String>): List<IPeripheral> {
        TODO("Not yet implemented")
    }

    override fun scan(timeout: Duration): Flow<IScanResult> {
        return callbackFlow {
            awaitClose {
                centralManager.stopScan()
            }
            centralManager.scanForPeripheralsWithServices(null, null)
            protocol.scanResultFlow
                .collect {
                    it?.let {
                        send(it)
                    }
            }
            close()
        }
    }

    override suspend fun connect(peripheral: IPeripheral) {
        TODO("Not yet implemented")
    }

    override val state: StateFlow<ICentralManager.State>
        get() = TODO("Not yet implemented")

    override fun close() {
        TODO("Not yet implemented")
    }
}

class  NativeCentralManagerProtocol: NSObject(), CBCentralManagerDelegateProtocol {

    val scanResultFlow = MutableStateFlow<IScanResult?>(null)

    override fun centralManagerDidUpdateState(central: CBCentralManager) {
        TODO("Not yet implemented")
    }

    override fun centralManager(
        central: CBCentralManager,
        didDiscoverPeripheral: CBPeripheral,
        advertisementData: Map<Any?, *>,
        RSSI: NSNumber
    ) {
        NativeScanResult(didDiscoverPeripheral, advertisementData, RSSI)
            .apply {
                scanResultFlow.emit(this)
            }

    }
}